/**
 * @file easy_led.c
 * @author 不咸不要钱 (main_2018@163.com)
 * @brief  led驱动文件
 * @version 0.1
 * @date 2021-11-24
 * 
 * @copyright Copyright (c) 2019
 * 
 */
#include "easy_led.h"

/** 指向led驱动链表头节点 */
static eLED_T * s_ledHead = 0;

extern void eled_port_init(void);
extern void eled_port_lock(void);
extern void eled_port_unlock(void);

/*!
  * @brief    led翻转处理
  *
  * @param    eLed    :led对象
  * @param    onTicks :一个闪烁周期中亮的节拍数
  * @param    offTicks:一个闪烁周期中暗的节拍数
  *
  * @return   无
  *
  * @note     内部调用
  *
  * @see      
  */
static void eled_handler(eLED_T * eLed, uint16_t onTicks, uint16_t offTicks)
{
    if(1 == eLed->ulTicks)
    {
        if(1 >= onTicks)
        {
            /* 默认led不亮 */
            eLed->ledControl(0);
        }
        else
        {
            eLed->ledControl(1);
        }
    }
    else if(eLed->ulTicks >= onTicks)
    {
        eLed->ledControl(0);
    }
    
    if(eLed->ulTicks >= offTicks)
    {
        eLed->ulTicks = 0;
    }
}

/*!
  * @brief    led初始化
  *
  * @param    eLed          :led对象
  * @param    ledControl    :指向led控制函数（该函数有一个参数 参数为0时 LED 亮）
  * @param    ledOnDefaultTicks :默认状态闪烁时 led点亮的节拍数
  * @param    ledOffDefaultTicks:默认状态闪烁时 led关闭的节拍数
  *
  * @return   无
  *
  * @note     
  *
  * @see      
  */
void eled_init(eLED_T * eLed, ledControl_t ledControl, uint16_t ledOnDefaultTicks, uint16_t ledOffDefaultTicks)
{
    if(0 == s_ledHead)
    {
        eled_port_init();
    }
    
    eled_port_lock();
    
    eLed->ulTicks             = 0;
    eLed->ulLedOnDefaultTicks = ledOnDefaultTicks + 1;
    eLed->ulLedOffDefaultTicks= ledOnDefaultTicks + ledOffDefaultTicks;
    eLed->ulLedOnTicks        = 0;
    eLed->ulLedOffTicks       = 0;
    eLed->ulKeepTicks         = 0;
    eLed->ledControl          = ledControl;
    
    /* 防止重复初始化 */
    eLED_T * node = s_ledHead;
    
    while(node)
    {
        if(node == eLed)
        {
            eled_port_unlock();
            return;
        }
        else
        {
            node = node->ptNextLed;
        }
    }
    
    eLed->ptNextLed           = s_ledHead;
    s_ledHead = eLed;
    
    eled_port_unlock();
}

/*!
  * @brief    led状态设置
  *
  * @param    eLed       :  led对象
  * @param    ledOnTicks : 一个闪烁周期 led点亮的节拍数
  * @param    ledOffTicks: 一个闪烁周期 led关闭的节拍数
  * @param    keepTicks  : led闪烁持续时间 为0xFFFF时 永久持续
  *
  * @return   无
  *
  * @note     当闪烁持续时间结束后 会按初始化时设置的默认状态进行闪烁
  *
  * @see      
  */
void eled_set(eLED_T * eLed, uint16_t ledOnTicks, uint16_t ledOffTicks, uint16_t keepTicks)
{
    eled_port_lock();
    
    eLed->ulTicks             = 0;
    eLed->ulLedOnTicks        = ledOnTicks + 1;
    eLed->ulLedOffTicks       = ledOnTicks + ledOffTicks;
    eLed->ulKeepTicks         = keepTicks;
    
    eled_port_unlock();
}

/*!
  * @brief    led默认状态设置
  *
  * @param    eLed       :  led对象
  * @param    ledOnDefaultTicks :默认状态闪烁时 led点亮的节拍数
  * @param    ledOffDefaultTicks:默认状态闪烁时 led关闭的节拍数
  *
  * @return   无
  *
  * @note     当闪烁持续时间结束后 会按初始化时设置的默认状态进行闪烁
  *
  * @see      
  */
void eled_set_default(eLED_T * eLed, uint16_t ledOnDefaultTicks, uint16_t ledOffDefaultTicks)
{
    eled_port_lock();
    
    eLed->ulLedOnDefaultTicks = ledOnDefaultTicks + 1;
    eLed->ulLedOffDefaultTicks= ledOnDefaultTicks + ledOffDefaultTicks;
    
    eled_port_unlock();
}

/*!
  * @brief    led停止闪烁
  *
  * @param    eLed       :  led对象
  *
  * @return   无
  *
  * @note     将该led从链表移除
  *
  * @see      
  */
void eled_stop(eLED_T * eLed)
{
    eLED_T** curr;
    for(curr = &s_ledHead; *curr; ) 
    {
        eLED_T* entry = *curr;
        if (entry == eLed) 
        {
            eled_port_lock();
            *curr = entry->ptNextLed;
            eled_port_unlock();
            return;
        } 
        else
            curr = &entry->ptNextLed;
	}
}

/*!
  * @brief    led 节拍处理
  *
  * @param    无
  *
  * @return   无
  *
  * @note     需要周期性执行  闪烁时间设置均以该周期为单位
  *
  * @see      
  */
void eled_ticks(void)
{
    eLED_T * target = s_ledHead;
	
    eled_port_lock();
    
    while(target)
    {
        if(target->ulTicks == TICKS_MAX)
        {
            target->ulTicks = 0;
        }

            target->ulTicks ++;
            
        if(0 == target->ulKeepTicks)
        {
            eled_handler(target, target->ulLedOnDefaultTicks, target->ulLedOffDefaultTicks);
        }
        else
        {
            eled_handler(target, target->ulLedOnTicks, target->ulLedOffTicks);
            target->ulKeepTicks --;
        }
            
        target = target->ptNextLed;
    }
    
    eled_port_unlock();
}
